package npcSystem;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import levelSystem.*;
import mapSystem.Tile;

import tools.Physics;
import tools.Rect;
import tools.Constants;

public abstract class NPC {

	protected MapLevel curLevel;
	
	protected Rect me;
	
	protected boolean moving;
	protected double vel;
	protected double xVel;
	protected double yVel;
	protected int levelWidth;
	protected int levelHeight;
	
    protected boolean imune;
    protected int imuneTime;
    protected int maxImuneTime;
    
    protected boolean knockedBack;
    protected int knockedBackTime;
    protected int maxKnockedBackTime;
    
    protected int health;
    protected int maxHealth;
	protected boolean dead;
	protected int deadFrames;
	protected int maxDeadFrames;
	
	protected int curDir;
	protected int curFrame;
	protected int frameSkipCount;
	protected int maxFrameSkip;

	protected boolean spawning;
	
    protected Rect cam;
	
    protected boolean attacking;
	protected int maxCurFrame;
	
	protected BufferedImage sprite;	
	protected Rect clips[][];
	
	/* Funcionamento dos clips:
	 * primeira chave: direcao
	 * 1(0) - esquerda
	 * 2(1) - direita
	 * 3(2) - cima
	 * 4(3) - baixo
	 * segunda chave: imagem atual(curFrame)
	 * curFrame		- incrementado a cada frame:
	 * maxCurFrame  - sprite width / me width
	 * ---------------------------
	 * Sequencia de movimento:
	 * 0~3   - andar
	 * 4~7   - parado
	 * 8~11  - morto - nao implementado
	 * 11+	 - implementado pela classe
	 * ---------------------------
	 * Sequencia de ataque:
	 * 0~3  - atacando - pode ser variado pela classe
	 * 3+ 	- implementado pela classe
	 * */
	
	public NPC() { // inicializa todas as variaveis, atribuicoes sao feitas por cada filho
		curLevel = null;
		
		me = new Rect();
		moving = false;
		vel = 0;
		xVel = 0;
		yVel = 0;
		levelWidth = 0;
		levelHeight = 0;
		
		imune = false;
		imuneTime = 0;
		maxImuneTime = 0;
		
		knockedBack = false;
		knockedBackTime = 0;
		maxKnockedBackTime = 0;
		
		spawning = false;
		
		health = 0;
		dead = false;
		deadFrames = 0;
		maxDeadFrames = 0;
		maxHealth = 0;
		
		curDir = 0;
		curFrame = 0;
		frameSkipCount = 0;
		maxFrameSkip = 0;
		
		attacking = false;
		maxCurFrame = 0;
		
		sprite = null;
		clips = null;
		
		cam = null;
	}
	
	public abstract void move();
	protected boolean hitWall(ArrayList<Tile> showingWalls)
    {
        for(Tile t : curLevel.getShowingWalls())
        {
            if(Physics.checkBlockCollision(t.getRect(), me))
            {
                return true;
            }
        }
        return false;
    }
	
	public abstract int logic();
	
	public void draw(Graphics g){
		
		if(!curLevel.isPaused()) setCurFrame();
		if(dead) drawDeadSprites(g);
		else if(spawning) drawSpawningSprites(g);
		else if(attacking) drawAttackSprites(g);
        else if(moving) drawMovingSprites(g);
        else drawStopSprites(g);
        
//        g.setColor(Color.green); // DEBUG
//        g.fillRect((int)me.x, (int)me.y,(int) me.w, (int)me.h);
	}
	protected void setCurFrame()
    {
		frameSkipCount++;
        if(frameSkipCount >= maxFrameSkip)
        {
        	curFrame++;
            if(curFrame >= sprite.getWidth()/Constants.TILE_WIDTH)
            {
                curFrame = 0;
                if(attacking) attacking = false;
            	if(spawning)spawning = false;
            }
            frameSkipCount = 0;
        }
    }
    protected void drawSpawningSprites(Graphics g)
    {
    	g.drawImage(sprite.getSubimage((int)clips[curDir+7][curFrame].x, 
				   (int)clips[curDir+7][curFrame].y, 
				   (int)clips[curDir+7][curFrame].w, 
				   (int)clips[curDir+7][curFrame].h), 
				   (int)(me.x - cam.x), 
				   (int)(me.y - cam.y), null);
    }
	protected void drawDeadSprites(Graphics g)// implementar
    {
		g.drawImage(sprite.getSubimage((int)clips[curDir+7][3-curFrame].x, 
				   (int)clips[curDir+7][3-curFrame].y, 
				   (int)clips[curDir+7][3-curFrame].w, 
				   (int)clips[curDir+7][3-curFrame].h), 
				   (int)(me.x - cam.x), 
				   (int)(me.y - cam.y), null);
    }
	protected void drawMovingSprites(Graphics g)
    {
    	g.drawImage(sprite.getSubimage((int)clips[curDir-1][curFrame].x, 
				   (int)clips[curDir-1][curFrame].y, 
				   (int)clips[curDir-1][curFrame].w, 
				   (int)clips[curDir-1][curFrame].h), 
				   (int)(me.x - cam.x), 
				   (int)(me.y - cam.y), null);
    }
    protected void drawStopSprites(Graphics g)
    {
    	g.drawImage(sprite.getSubimage((int)clips[curDir+3][curFrame].x, 
				   (int)clips[curDir+3][curFrame].y, 
				   (int)clips[curDir+3][curFrame].w, 
				   (int)clips[curDir+3][curFrame].h), 
				   (int)(me.x - cam.x), 
				   (int)(me.y - cam.y), null);
    }   
    protected void drawAttackSprites(Graphics g) // NPC ataca andando
    {
    	g.drawImage(sprite.getSubimage((int)clips[curDir-1][curFrame].x, 
				   (int)clips[curDir-1][curFrame].y, 
				   (int)clips[curDir-1][curFrame].w, 
				   (int)clips[curDir-1][curFrame].h), 
				   (int)(me.x - cam.x), 
				   (int)(me.y - cam.y), null);
    }
	
	public Rect getMe()
	{
		return me;
	}
	public double getX()
	{
		return me.x;
	}
	public double getY()
	{
		return me.y;
	}
	public double getVel()
	{
		return vel;
	}
	public double getxVel()
    {
    	return xVel;
    }
    public double getyVel()
    {
    	return yVel;
    }
    public double getWidth()
    {
    	return me.w;
    }
    public double getHeight()
    {
    	return me.h;
    }
    
    public boolean isImune()
    {
    	return imune;
    }
    public void calcImuneTime()
    {
    	imuneTime++;
    	if(imuneTime >= maxImuneTime)
    	{
    		imuneTime = 0;
    		imune = false;
    	}
    }
    
    public void calcKnockedTime()
    {
    	knockedBackTime++;
    	if(knockedBackTime >= maxKnockedBackTime)
    	{
    		knockedBack = false;
    		knockedBackTime = 0;
    	}
    }
    
    public void checkIfIsDead()
    {
    	if(health <= 0) dead = true;
    }
    
    public void setVel(Double v)
    {
    	vel = v;
    	if(yVel > 0)
    	{
    		yVel = 0;
    		yVel += vel;
    	}else if(yVel < 0)
    	{
    		yVel = 0;
    		yVel -= vel;
    	}
    	if(xVel > 0)
    	{
    		xVel = 0;
    		xVel += vel;
    	}else if(xVel < 0)
    	{
    		xVel = 0;
    		xVel -= vel;
    	}
    }
	
    public int getHealth()
    {
    	return health;
    }
    public int getMaxHealth()
    {
    	return maxHealth;
    }
    
	protected void initClips()
    {
		int rows = sprite.getHeight()/Constants.TILE_HEIGHT;
		int cols = sprite.getWidth()/Constants.TILE_WIDTH;
		
        for(int i = 0; i < rows; i++)
        {
            for(int k = 0; k < cols; k++)
            {
                clips[i][k] = new Rect();
            }
        }
    }
    protected void setClips() 
    {
    	int rows = sprite.getHeight()/Constants.TILE_HEIGHT;
		int cols = sprite.getWidth()/Constants.TILE_WIDTH;
    	
		// [n][0 a 3]   = parado
		// [n][4 a 7]   = movendo
		// [n][8 a 11]  = atacando (ataque fraco no mainChar)
		// [n][12 a 15] = atacando (ataque forte no mainChar) -> existe somente para o player
		
        for(int i = 0; i < rows; i++)
        {
            for(int k = 0; k < cols; k++)
            {
//                clips[i][k].y = i*Constants.NPC_DEFAULT_SPRITE_HEIGHT;
//                clips[i][k].x = k*Constants.NPC_DEFAULT_SPRITE_WIDTH;
//                clips[i][k].w = Constants.NPC_DEFAULT_SPRITE_WIDTH;
//                clips[i][k].h = Constants.NPC_DEFAULT_SPRITE_HEIGHT;
            	clips[i][k].y = i*Constants.TILE_HEIGHT;
                clips[i][k].x = k*Constants.TILE_WIDTH;
                clips[i][k].w = Constants.TILE_WIDTH;
                clips[i][k].h = Constants.TILE_HEIGHT;
            }
        }
    }

    public void setPos(double x, double y)
    {
        me.x = x;
        me.y = y;
    }
}
